/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.bizfty.apiexecutor.classloader;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author johns
 */
public class ExecutorClassLoader extends URLClassLoader {

    private static final Logger logger = LoggerFactory.getLogger(ExecutorClassLoader.class);

    private Map<String,List<JarURLConnection>> cached = new HashMap<>();

    public ExecutorClassLoader(URL[] urls) {
        super(urls);
    }
    public ExecutorClassLoader(String path) {
        super(ExecutorClassLoader.getUrls(path), findParentClassLoader());
    }
    public ExecutorClassLoader(String path,ClassLoader parent) {
        super(ExecutorClassLoader.getUrls(path), parent);
    }

    public ExecutorClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {
        logger.debug("加载Class:【" + name + "】");
        return super.findClass(name);
    }

    /**
     * 将指定的文件url添加到类加载器的classpath中去，并缓存jar connection，方便以后卸载jar
     *
     * @param file 一个可想类加载器的classpath中添加的文件url
     * @param moduleId 模块名称
     */
    public void loadJarFile(URL file, String moduleId) {
        URLConnection uc;
        try {
            uc = file.openConnection();
            if (uc instanceof JarURLConnection) {
                uc.setUseCaches(true);
            }
            ((JarURLConnection) uc).getManifest();
            List<JarURLConnection> jars = cached.get(moduleId);
            if(jars==null){
                jars = new ArrayList<JarURLConnection>();
            }
            jars.add((JarURLConnection) uc);
        } catch (IOException ex) {
            logger.error("module:"+moduleId+",加载jar:"+file, ex);
        }
        addURL(file);
    }
    /**
     * 卸载jar包
     * @param moduleId 模块ID
     */
    public void unloadJarFiles(String moduleId){
        List<JarURLConnection> jars = cached.get(moduleId);
        for (JarURLConnection url : jars) {
            try {
                logger.debug("Unloading plugin JAR file " + url.getJarFile().getName());
                url.getJarFile().close();
            } catch (IOException ex) {
                logger.error("卸载jar", ex);
            }
        }
        cached.remove(moduleId);
    }
    
    private static ClassLoader findParentClassLoader() {
        ClassLoader parent = Thread.currentThread().getContextClassLoader();
        if (parent == null) {
            parent = ExecutorClassLoader.class.getClassLoader();
        }
        if (parent == null) {
            parent = ClassLoader.getSystemClassLoader();

        }
        return parent;

    }
    public static URL[] getUrls(String path) {
        File fileDir = new File(path);
        File[] files = fileDir.listFiles();
        List<URL> urls = new ArrayList<>();
        if (files == null || files.length < 1) {
            return new URL[0];
        }
        for (File f : files) {
            URI fu = f.toURI();
            try {
                urls.add(fu.toURL());
            } catch (MalformedURLException ex) {
                logger.error("转url异常", ex);
            }
        }
        URL[] us = new URL[urls.size()];
        return urls.toArray(us);
    }
}
